﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MotionCS.Helper;
using MotionCS.Config;

namespace MotionCS.Controller
{
    public class MotionDevice : SingleObjectBase<MotionDevice>
    {
        private enum CardTypeE
        {
            /// <summary>
            /// 升立德9014
            /// </summary>
            PCI9014,
            /// <summary>
            /// 雷赛3000
            /// </summary>
            SMC3000,
            /// <summary>
            /// 正运动
            /// </summary>
            ZMotion
        }
        /// <summary>
        /// 日志回调
        /// </summary>
        public Action<string> LogCallback { get; set; }
        /// <summary>
        /// 运动轴集合
        /// </summary>
        private List<IAxis> AxisList;
        /// <summary>
        /// Di输入集合
        /// </summary>
        private List<IDiBit> DiList;
        /// <summary>
        /// Do输出集合
        /// </summary>
        private List<IDoBit> DoList;
        /// <summary>
        /// 比较器
        /// </summary>
        public LeadshineCompare Compare;
        /// <summary>
        /// 卡数量
        /// </summary>
        private int cardCount;
        /// <summary>
        /// 卡ID
        /// </summary>
        private int[] cardId = new int[16];
        /// <summary>
        /// 默认构造函数
        /// </summary>
        /// 
        public bool m_bUseSafedoor = true;
        /// <summary>
        /// 是否使用安全门
        /// </summary>
        /// 

        public MotionDevice()
        {
            AxisList = new List<IAxis>();
            DiList = new List<IDiBit>();
            DoList = new List<IDoBit>();
        }
        /// <summary>
        /// 初始化
        /// </summary>
        public void Init()
        {
            InitBoard();
            InitIOPort();
            InitAxis();
        }
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Uninit()
        {
            AxisList.ForEach(p => p.EmgStop());
            DoList.ForEach(p => p.TurnOff());
            UnitBoard();
        }

        public bool IsConnected()
        {
            bool connected = false;
            switch ((CardTypeE)HardwareConfi.Instance.MotionConfi.MotionCardType)
            {
                case CardTypeE.SMC3000:
                    connected = Smc300Api.IsOpen;
                    break;
                case CardTypeE.ZMotion:
                    break;
                default:
                    connected = Pci9014Api.IsOpen;
                    break;
            }
            return connected;
        }

        /// <summary>
        /// 运动轴急停
        /// </summary>
        public void AxisEmgStop()
        {
            AxisList.ForEach(p => p.EmgStop());
        }
        /// <summary>
        /// 初始化控制卡
        /// </summary>
        private void InitBoard()
        {
            switch ((CardTypeE)HardwareConfi.Instance.MotionConfi.MotionCardType)
            {
                case CardTypeE.SMC3000:
                    Smc300Api.LogCallback = LogCallback;
                    Smc300Api.BoardInit();
                    break;
                case CardTypeE.ZMotion:
                    break;
                default:
                    Pci9014Api.LogCallback = LogCallback;
                    Pci9014Api.Initial(ref cardCount, cardId);
                    break;
            }
        }
        /// <summary>
        /// 释放控制卡
        /// </summary>
        private void UnitBoard()
        {
            switch ((CardTypeE)HardwareConfi.Instance.MotionConfi.MotionCardType)
            {
                case CardTypeE.SMC3000:
                    Smc300Api.BoardClose();
                    break;
                case CardTypeE.ZMotion:
                    break;
                default:
                    Pci9014Api.close();
                    break;
            }
        }
        /// <summary>
        /// 实例划轴
        /// </summary>
        /// <returns></returns>
        private void InstanceAxis(AxisConfi config)
        {
            IAxis axis;

            if (config.Axis == -1)
            {
                //LogCallback?.Invoke($"{config.Identity}未启用.");
                return;
            }

            switch ((CardTypeE)HardwareConfi.Instance.MotionConfi.MotionCardType)
            {
                case CardTypeE.SMC3000:
                    if (config.Axis >= 1000)
                    {
                        axis = new Dm2cAxis(config);
                    }
                    else
                    {
                        axis = new Smc300Axis(config);
                    }
                    break;
                default:
                    axis = new Pci9014Axis(config);
                    break;
            }

            AxisList.Add(axis);
        }
        /// <summary>
        /// 实例化Di
        /// </summary>
        /// <param name="id"></param>
        /// <param name="bit"></param>
        /// <returns></returns>
        private void InstanceDi(DiE id, int bit)
        {
            IDiBit dibit;

            if (bit == -1) return;

            switch ((CardTypeE)HardwareConfi.Instance.MotionConfi.MotionCardType)
            {
                case CardTypeE.SMC3000:
                    dibit = new Smc300Di((int)id, (ushort)bit);
                    break;
                default:
                    dibit = new Pci9014Di((int)id, (ushort)bit);
                    break;
            }

            DiList.Add(dibit);
        }
        /// <summary>
        /// 实例化Do
        /// </summary>
        /// <param name="id"></param>
        /// <param name="bit"></param>
        /// <returns></returns>
        private void InstanceDo(DoE id, int bit)
        {
            IDoBit dobit;

            if (bit == -1) return;

            switch ((CardTypeE)HardwareConfi.Instance.MotionConfi.MotionCardType)
            {
                case CardTypeE.SMC3000:
                    dobit = new Smc300Do((int)id, (ushort)bit);
                    break;
                default:
                    dobit = new Pci9014Do((int)id, (ushort)bit);
                    break;
            }

            DoList.Add(dobit);
        }
        /// <summary>
        /// 初始化IO
        /// </summary>
        private void InitIOPort()
        {
            InstanceDi(DiE.StartBtn, HardwareConfi.Instance.DInConfi.Start);
            InstanceDi(DiE.ResetBtn, HardwareConfi.Instance.DInConfi.Reset);
            InstanceDi(DiE.StopBtn, HardwareConfi.Instance.DInConfi.Stop);
            InstanceDi(DiE.SafeDoor, HardwareConfi.Instance.DInConfi.SafeDoor);
            InstanceDi(DiE.T1Sensor1, HardwareConfi.Instance.DInConfi.T1Sensor1);
            InstanceDi(DiE.T1Sensor2, HardwareConfi.Instance.DInConfi.T1Sensor2);
            InstanceDi(DiE.T1Sensor3, HardwareConfi.Instance.DInConfi.T1Sensor3);
            InstanceDi(DiE.T1Sensor4, HardwareConfi.Instance.DInConfi.T1Sensor4);
            InstanceDi(DiE.EmgStop, HardwareConfi.Instance.DInConfi.EmgStop);
            InstanceDi(DiE.Pressure, HardwareConfi.Instance.DInConfi.Pressure);
            InstanceDi(DiE.T1PassMode, HardwareConfi.Instance.DInConfi.T1PassMode);
            InstanceDi(DiE.T1FrontReady, HardwareConfi.Instance.DInConfi.T1FrontReady);
            InstanceDi(DiE.T1AfterReady, HardwareConfi.Instance.DInConfi.T1AfterReady);

            InstanceDi(DiE.T2Sensor1, HardwareConfi.Instance.DInConfi.T2Sensor1);
            InstanceDi(DiE.T2Sensor2, HardwareConfi.Instance.DInConfi.T2Sensor2);
            InstanceDi(DiE.T2Sensor3, HardwareConfi.Instance.DInConfi.T2Sensor3);
            InstanceDi(DiE.T2Sensor4, HardwareConfi.Instance.DInConfi.T2Sensor4);
            InstanceDi(DiE.T2PassMode, HardwareConfi.Instance.DInConfi.T2PassMode);
            InstanceDi(DiE.T2FrontReady, HardwareConfi.Instance.DInConfi.T2FrontReady);
            InstanceDi(DiE.T2AfterReady, HardwareConfi.Instance.DInConfi.T2AfterReady);

            InstanceDo(DoE.CameraUpStrobeR, HardwareConfi.Instance.DOutConfi.CameraUpStrobeR);
            InstanceDo(DoE.CameraUpStrobeG, HardwareConfi.Instance.DOutConfi.CameraUpStrobeG);
            InstanceDo(DoE.CameraUpStrobeB, HardwareConfi.Instance.DOutConfi.CameraUpStrobeB);
            InstanceDo(DoE.CameraUpStrobeW, HardwareConfi.Instance.DOutConfi.CameraUpStrobeW);
            InstanceDo(DoE.CameraUpTrigger, HardwareConfi.Instance.DOutConfi.CameraUpTrigger);
            InstanceDo(DoE.CameraUpLeftDlp, HardwareConfi.Instance.DOutConfi.CameraUpLeftDlp);
            InstanceDo(DoE.CameraUpFrontDlp, HardwareConfi.Instance.DOutConfi.CameraUpFrontDlp);
            InstanceDo(DoE.CameraUpRightDlp, HardwareConfi.Instance.DOutConfi.CameraUpRightDlp);
            InstanceDo(DoE.CameraUpBackDlp, HardwareConfi.Instance.DOutConfi.CameraUpBackDlp);
            InstanceDo(DoE.CameraDownStrobeR, HardwareConfi.Instance.DOutConfi.CameraDownStrobeR);
            InstanceDo(DoE.CameraDownStrobeG, HardwareConfi.Instance.DOutConfi.CameraDownStrobeG);
            InstanceDo(DoE.CameraDownStrobeB, HardwareConfi.Instance.DOutConfi.CameraDownStrobeB);
            InstanceDo(DoE.CameraDownStrobeW, HardwareConfi.Instance.DOutConfi.CameraDownStrobeW);
            InstanceDo(DoE.CameraDownTrigger, HardwareConfi.Instance.DOutConfi.CameraDownTrigger);
            InstanceDo(DoE.CameraDownLeftDlp, HardwareConfi.Instance.DOutConfi.CameraDownLeftDlp);
            InstanceDo(DoE.CameraDownFrontDlp, HardwareConfi.Instance.DOutConfi.CameraDownFrontDlp);
            InstanceDo(DoE.CameraDownRightDlp, HardwareConfi.Instance.DOutConfi.CameraDownRightDlp);
            InstanceDo(DoE.CameraDownBackDlp, HardwareConfi.Instance.DOutConfi.CameraDownBackDlp);
            InstanceDo(DoE.T1Cylinder1, HardwareConfi.Instance.DOutConfi.T1Cylinder1);
            InstanceDo(DoE.T1Cylinder2, HardwareConfi.Instance.DOutConfi.T1Cylinder2);
            InstanceDo(DoE.T1Cylinder3, HardwareConfi.Instance.DOutConfi.T1Cylinder3);
            InstanceDo(DoE.T1FrontReady, HardwareConfi.Instance.DOutConfi.T1FrontReady);
            InstanceDo(DoE.T1AfterReady, HardwareConfi.Instance.DOutConfi.T1AfterReady);
            InstanceDo(DoE.T1CheckReady, HardwareConfi.Instance.DOutConfi.T1CheckResult);
            InstanceDo(DoE.T1Red, HardwareConfi.Instance.DOutConfi.T1StatusR);
            InstanceDo(DoE.T1Green, HardwareConfi.Instance.DOutConfi.T1StatusG);
            InstanceDo(DoE.T1Yellow, HardwareConfi.Instance.DOutConfi.T1StatusY);
            InstanceDo(DoE.T1Beep, HardwareConfi.Instance.DOutConfi.T1AlmBeep);
            InstanceDo(DoE.T2Cylinder1, HardwareConfi.Instance.DOutConfi.T2Cylinder1);
            InstanceDo(DoE.T2Cylinder2, HardwareConfi.Instance.DOutConfi.T2Cylinder2);
            InstanceDo(DoE.T2Cylinder3, HardwareConfi.Instance.DOutConfi.T2Cylinder3);
            InstanceDo(DoE.T2FrontReady, HardwareConfi.Instance.DOutConfi.T2FrontReady);
            InstanceDo(DoE.T2AfterReady, HardwareConfi.Instance.DOutConfi.T2AfterReady);
            InstanceDo(DoE.T2CheckReady, HardwareConfi.Instance.DOutConfi.T2CheckResult);
            InstanceDo(DoE.T2Red, HardwareConfi.Instance.DOutConfi.T2StatusR);
            InstanceDo(DoE.T2Green, HardwareConfi.Instance.DOutConfi.T2StatusG);
            InstanceDo(DoE.T2Yellow, HardwareConfi.Instance.DOutConfi.T2StatusY);
            InstanceDo(DoE.T2Beep, HardwareConfi.Instance.DOutConfi.T2AlmBeep);

            DoList.ForEach(p => p.TurnOff());
        }

        /// <summary>
        /// 初始化轴
        /// </summary>
        private void InitAxis()
        {
            InstanceAxis(HardwareConfi.Instance.XAxisUpConfi);
            InstanceAxis(HardwareConfi.Instance.YAxisUpConfi);
            InstanceAxis(HardwareConfi.Instance.WAxisFrontConfi);
            InstanceAxis(HardwareConfi.Instance.TAxisFrontConfi);

            InstanceAxis(HardwareConfi.Instance.XAxisDownConfi);
            InstanceAxis(HardwareConfi.Instance.YAxisDownConfi);
            InstanceAxis(HardwareConfi.Instance.TAxisBackConfi);
            InstanceAxis(HardwareConfi.Instance.WAxisBack1Confi);
            InstanceAxis(HardwareConfi.Instance.WAxisBack2Confi);
        }
        /// <summary>
        /// 获取轴实例
        /// </summary>
        /// <param name="axis"></param>
        /// <returns></returns>
        public IAxis GetAxis(AxisEnum axis)
        {
            return AxisList.Find(p => p.Config.Identity == axis);
        }
        /// <summary>
        /// 获取输入端口实例
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public IDiBit DiBit(DiE id)
        {
            return DiList.Find(f => f.Identity == (int)id);
        }
        /// <summary>
        /// 获取输出端口实例
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public IDoBit DoBit(DoE id)
        {
            return DoList.Find(f => f.Identity == (int)id);
        }
        /// <summary>
        /// 获取输入端口
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public int GetDiBit(DiE id)
        {
            return DiList.Find(f => f.Identity == (int)id).Index;
        }
        /// <summary>
        /// 获取输出端口
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public int GetDoBit(DoE id)
        {
            return DoList.Find(f => f.Identity == (int)id).Index;
        }
        /// <summary>
        /// 指定输入端口是否导通
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool DiIsOn(DiE id)
        {
            return DiList.Find(f => f.Identity == (int)id).IsOn();
        }
        /// <summary>
        /// 指定输入端口是否断开
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool DiIsOff(DiE id)
        {
            return DiList.Find(f => f.Identity == (int)id).IsOff();
        }
        /// <summary>
        /// 设置Do输出
        /// </summary>
        /// <param name="bit"></param>
        /// <param name="val"></param>
        public void SetDoBit(int bit, int val)
        {
            DoList.Find(f => f.Index == bit).SetOut((uint)val);
        }
        /// <summary>
        /// 设置Do输出
        /// </summary>
        /// <param name="id"></param>
        /// <param name="val"></param>
        public void SetDoBit(DoE id, int val)
        {
            DoList.Find(f => f.Identity == (int)id).SetOut((uint)val);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
	  	public void TurnOn(DoE id)
        {
            DoList.Find(f => f.Identity == (int)id).TurnOn();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        public void TurnOff(DoE id)
        {
            DoList.Find(f => f.Identity == (int)id).TurnOff();
        }
        /// <summary>
        /// 读取输入端口
        /// </summary>
        public uint ReadInport(int icardId)
        {
            uint port = 0;

            switch ((CardTypeE)HardwareConfi.Instance.MotionConfi.MotionCardType)
            {
                case CardTypeE.SMC3000:
                    //dobit = null;//new Smc300Axis();
                    break;
                default:
                    Pci9014Api.get_di(cardId[icardId], ref port);
                    break;
            }

            return port;
        }
        /// <summary>
        /// 读取输出端口
        /// </summary>
        public uint ReadOutport(int icardId)
        {
            uint port = 0;
            
            switch ((CardTypeE)HardwareConfi.Instance.MotionConfi.MotionCardType)
            {
                case CardTypeE.SMC3000:
                    //dobit = null;//new Smc300Axis();
                    break;
                default:
                    Pci9014Api.get_do(cardId[icardId], ref port);
                    break;
            }

            return port;
        }
    }
}